# coding: utf-8

'''
Auteur shin
Date   11/05/2011 
'''

import sys
from PyQt4 import QtGui, QtCore
import random

# ================================== CLASS ===============================
# ========================================================================
class Personnage():
    def __init__(self, type, race):
        '''
        Constructor
        ''' 
        self.objet = ""
        self.type = ""
        self.hauteur = 0
        self.constitution = 0
        self.taille = 0
        self.degats = 0
        self.franchissable = True
        self.joueur = 0
        self.endurance = 0
        self.intelligence = 0
        self.energie = 0
        self.cible = ""
        self.competence = ["mouvement"]
        self.nom = ""
        
        if (type == "Guerrier" and race == "Nain"):
            self.objet = "Personnage"
            self.type = "Vivant"
            self.hauteur = 0
            self.constitution = 8
            self.taille = 1.2
            self.degats = 5
            self.franchissable = False
            self.joueur = 0
            self.endurance = 7
            self.intelligence = 7
            self.energie = 100
            self.cible = ""
            self.nom = "Rankor"

        if (type == "Archer" and race == "Elfe"):
            self.objet = "Personnage"
            self.type = "Vivant"
            self.hauteur = 0
            self.constitution = 5
            self.taille = 2.0
            self.degats = 3
            self.franchissable = False
            self.joueur = 0
            self.endurance = 9
            self.intelligence = 10
            self.energie = 120
            self.cible = ""
            self.nom = "Shu"

        if (type == "Mage" and race == "Mort-Vivant"):
            self.objet = "Personnage"
            self.type = "Mort-Vivant"
            self.hauteur = 0
            self.constitution = 9
            self.taille = 1.7
            self.degats = 4
            self.franchissable = False
            self.joueur = 0
            self.endurance = 6
            self.intelligence = 5
            self.energie = 80
            self.cible = ""
            self.nom = "Asura"

        if (type == "DeathKnight" and race == "BloodElfe"):
            self.objet = "Personnage"
            self.type = "Vivant"
            self.hauteur = 0
            self.constitution = 8
            self.taille = 1.6
            self.degats = 4
            self.franchissable = False
            self.joueur = 0
            self.endurance = 7
            self.intelligence = 7
            self.energie = 120
            self.cible = ""
            self.nom = "Mantas"
            
    def recuperationEnergie(self):
        return self.endurance * 2

    def mouvement(self):
        return self.endurance//2

    def initiative(self):
        return self.endurance//2 + self.intelligence//2



class UiTour(QtGui.QWidget):
    def __init__(self, parent):
        super(UiTour, self).__init__(parent)

        self.font = QtGui.QWidget(self)
        self.font.resize(300, 300)
        self.font.setStyleSheet("QWidget { background-color: %s }" % 
                                QtGui.QColor(200, 200, 200).name() )
        
        self.label_titre = QtGui.QLabel("Tour", self)
        self.label_titre.move(5,0)
        
        self.label_text  = QtGui.QLabel("", self)
        self.label_text.move(15,20)
        self.label_text.resize(185,15)
        
    def maj(self, text):
        self.label_text.setText(text)

class UiActivite(QtGui.QWidget):
    def __init__(self, parent):
        super(UiActivite, self).__init__(parent)

        self.font = QtGui.QWidget(self)
        self.font.resize(300, 700)
        self.font.setStyleSheet("QWidget { background-color: %s }" % 
                                QtGui.QColor(200, 200, 200).name() )
        
        self.label_titre = QtGui.QLabel("Activite", self)
        self.label_titre.move(5,0)
        
        self.label_deroulement = QtGui.QLabel("aa", self)
        self.label_deroulement.move(15,20)
        self.label_deroulement.resize(185,200)
        
    def maj_deroulement(self, texte):
        self.label_deroulement.setText(texte)    

class UiCase(QtGui.QWidget):
    def __init__(self, parent):
        super(UiCase, self).__init__(parent)

        self.font = QtGui.QWidget(self)
        self.font.resize(300, 300)
        self.font.setStyleSheet("QWidget { background-color: %s }" % 
                                QtGui.QColor(200, 200, 200).name() )
        
        self.label_titre = QtGui.QLabel("Case", self)
        self.label_titre.move(5,0)
        
        self.label_text  = QtGui.QLabel("", self)
        self.label_text.move(15,20)
        self.label_text.resize(185,10)
        
    def maj(self, type):
        self.label_text.setText(type)

class Case(QtGui.QWidget):
    def __init__(self, uiDamier, nomCase, uiCase):
        super(Case, self).__init__(uiDamier)
        self._uiCase = uiCase
        self.initUI(nomCase)
        
    def initUI(self, nomCase):
        self.name = nomCase
        self._type = terrain[nomCase]
        self.color = self._trouveCouleur(nomCase)
        self.font = QtGui.QWidget(self)
        self.font.resize(100,100)
        self.personnage = QtGui.QLabel("", self)
        self.personnage.move(10,10)
        self.personnage.resize(100,10)
        self.font.setStyleSheet("QWidget { background-color: %s }"
                                % self.color.name() )
        self.choixPossible = QtGui.QWidget(self)
        self.choixPossible.resize(20,20)
        self.choixPossible.move(25,20)
        self.choixPossible.setStyleSheet("QWidget { background-color: %s }"
                                         % self.color.name() )


    def _trouveCouleur(self, nomCase):
        color = QtGui.QColor(0, 0, 0)
        if (terrain[nomCase] == "Herbe"):
            color.setGreen(150)
        if (terrain[nomCase] == "Eau"):
            color.setBlue(150)
        if (terrain[nomCase] == "Rocher"):
            color.setGreen(150)
            color.setBlue(150)
            color.setRed(150)
        if (terrain[nomCase] == "Sable"):
            color.setRed(255)
            color.setGreen(250)
            color.setBlue(100)
        return color

    def mousePressEvent(self, mouseEvent):
        if mouseEvent.button() == QtCore.Qt.LeftButton:
            self._uiCase.maj(self._type)
            checkPersonnage(self.name)
        if mouseEvent.button() == QtCore.Qt.RightButton:
            if procedure == 1:
                realiseAction(self)
        
    def majPerso(self, nomPersonnage):
        self.personnage.setText(nomPersonnage)
        
    def supprimePersonnage(self):
        self.personnage.setText("")
        
    def reInitialiseCouleur(self):
        self.choixPossible.setStyleSheet("QWidget { background-color: %s }"
                                         % self.color.name() )

class UiDamier(QtGui.QWidget):
    def __init__(self, parent):
        super(UiDamier, self).__init__(parent)
        
        self.font = QtGui.QWidget(self)
        self.font.resize(1200, 1200)
        self.font.setStyleSheet("QWidget { background-color: %s }" % 
                                QtGui.QColor(200, 200, 200).name() )
        
        self.gridDamier = QtGui.QGridLayout()
        self.gridDamier.setSpacing(1)
        construitDamier(self)
        self.setLayout(self.gridDamier)

class UiPerso(QtGui.QWidget):
    def __init__(self, mainWindow, titre):
        
        super(UiPerso, self).__init__(mainWindow)
        
        self.font = QtGui.QWidget(self)
        self.font.resize(300, 300)
        self.font.setStyleSheet("QWidget { background-color: %s }" % 
                             QtGui.QColor(200, 200, 200).name() )
        
        self.label_titre = QtGui.QLabel(titre, self)
        self.label_titre.move(5,0)
        self.label_text  = QtGui.QLabel("", self)
        self.label_text.move(15,20)
        self.label_text.resize(185,120)

    def maj(self, personnage):
        self.label_text.setText(
            "nom : "          + personnage.nom               + "\n" +
            "type : "         + personnage.type              + "\n" +
            "hauteur : "      + str(personnage.hauteur)      + "\n" +
            "constitution : " + str(personnage.constitution) + "\n" +
            "taille : "       + str(personnage.taille)       + "\n" +
            "edurance : "     + str(personnage.endurance)    + "\n" +
            "intelligence : " + str(personnage.intelligence) + "\n" +
            "energie : "      + str(personnage.energie))
        
    def retire(self):
        self.label_text.setText("")

class LabelAction(QtGui.QLabel):
    def __init__(self, nom, parent):
        super(LabelAction, self).__init__(nom, parent)
        self._nom = nom
        self.move(15,20)
        self.resize(70, 25)
    
    def mousePressEvent(self, event):
        selectAction(self.text())

class UiAction(QtGui.QWidget):
    def __init__(self, mainWindow):
        
        super(UiAction, self).__init__(mainWindow)
        
        self.font = QtGui.QWidget(self)
        self.font.resize(600, 300)
        self.font.setStyleSheet("QWidget { background-color: %s }" % 
                             QtGui.QColor(200, 200, 200).name() )
        
        self.label_titre = QtGui.QLabel("Action", self)
        self.label_titre.move(5,0)
        self.label_action1  = LabelAction("", self)

    def maj(self, personnage):
        text = ""
        for competence in personnage.competence:
            text += competence
        self.label_action1.setText(text)
        
    def retire(self):
        self.label_action1.setText("")



def ajoutePersonnage(personnage, case):
    damier[case].append(personnage)
    damier[case][0].majPerso(personnage.nom)

def checkPersonnage(nomCase):
    global selected
    if ((len(damier[nomCase]) > 1)
            and (isinstance(damier[nomCase][1], Personnage)) ):
        personnage = damier[nomCase][1]
        
        uiPerso1.maj(personnage)
        
        if personnage.nom == prochainPersonnage[0]:
            uiAction.maj(personnage)
        else:
            uiAction.retire()

        if procedure == 0:
            selected = [personnage, nomCase]
    else:
        uiPerso1.retire()
        uiAction.retire()

def realiseAction(case):
    global selected, procedure, choice, action
    if action == "mouvement":
        if case.name in choice:
            
            # transfert du personnage
            damier[case.name].append(damier[selected[1]].pop(1))
            damier[case.name][0].majPerso(selected[0].nom)
            
            # calcul prochain tour du personnage
            prochainTourPersonnage()
            
            # nettoie derrière
            damier[selected[1]][0].supprimePersonnage()
            for nom in choice:
                damier[nom][0].reInitialiseCouleur()
            uiAction.retire()
            uiPerso1.retire()
            procedure = 0
            selected = None
            choice = None
            action = None
            prochainTour()
            
def selectAction(nom):
    if nom == "mouvement":
        for case in casePossible(selected[0].mouvement(), selected[1]):
            damier[case][0].choixPossible.setStyleSheet(
                                "QWidget { background-color: %s }"
                                % QtGui.QColor(170, 255, 0).name() )
        global procedure, action
        procedure = 1
        action = nom

def casePossible(mouvement, caseRef):
    x,y = ord(caseRef[0]), int(caseRef[1])
    list = []
    for i in range(0, mouvement + 1):
        for j in range(0, mouvement +1):
            if i+j > mouvement or i+j == 0: continue

            case = chr(x + i) + str(y + j)
            if case not in list\
                and case in damier.keys() :
                list.append(case)
            
            case = chr(x + i) + str(y - j)
            if case not in list\
                and case in damier.keys() :
                list.append(case)
            
            case = chr(x - i) + str(y + j)
            if case not in list\
                and case in damier.keys() :
                list.append(case)
            
            case = chr(x - i) + str(y - j)
            if case not in list\
                and case in damier.keys() :
                list.append(case)

    global choice
    choice = list
    return choice

def construitDamier(uiDamier):
    for y in range(0, terrain["largeur"]):
        for x in range(1, terrain["longueur"] + 1):
            # creation des cases
            nomCase = chr(65 + y) + str(x)
            damier[nomCase] = []
            damier[nomCase].append(Case(uiDamier, nomCase, uiCase))
            uiDamier.gridDamier.addWidget(damier[nomCase][0], x, y)

def calculOrdreInitialDeJeu():
    '''
    cette fonction permet d'initialiser le dictionnaire deroulement à partir
    de l'initiative des différents personnages.
    '''
    for case in damier: 
        if len(damier[case]) > 1:
            personnage = damier[case][1]
            timeKey = timer(personnage.initiative())
            actionTuple = (personnage.nom, 'tourDeJeu', None)
            if deroulement.has_key(timeKey):
                #crée une liste et met y l'actionTuple
                deroulement[timeKey].append(actionTuple)
            else:
                #ajoute l'actionTuple à la liste existante
                deroulement[timeKey] = [actionTuple]
    
def timer(initiative):
    '''
    calcul le temps correspondant à l'initiative
    '''
    return 10.0/initiative 

def prochainTour():
    # on récupère la liste trié des timeKeys
    timeKeys = deroulement.keys() 
    timeKeys.sort()
    
    # initialisation des global
    global tour, prochainPersonnage
    tour = timeKeys[0]
    prochainPersonnage = deroulement[tour][0]
    
    # on retire le premier élément pour l'afficher dans tour
    firstActionTuple = deroulement[tour].pop(0)
    uiTour.maj(str(tour)[0:3]
                + ') '
                + firstActionTuple[0]
                + ' : '
                + firstActionTuple[1])

    # on affiche les autres dans activité
    texte = ""
    for timeKey in timeKeys:
        for actionTuple in deroulement[timeKey]:
            texte += str(timeKey)[0:3]  \
                    + ") "              \
                    + (actionTuple[0])  \
                    + (" : ")           \
                    + (actionTuple[1])  \
                    + ("\n\n\n")
    uiActivite.maj_deroulement(texte)
    
    # on retire l'élément 0 si vide
    if deroulement[tour] == []:
        del deroulement[tour]

def prochainTourPersonnage():
    '''
        Permet de calculer le prochain tour de jeu du personnage
    qui vient de choisir son action.
    '''
    personnage = selected[0]
    timeKey = timer(personnage.initiative())
    timeKey += tour
    actionTuple = (personnage.nom, 'tourDeJeu', None)
    if deroulement.has_key(timeKey):
        #crée une liste et met y l'actionTuple
        deroulement[timeKey].append(actionTuple)
    else:
        #ajoute l'actionTuple à la liste existante
        deroulement[timeKey] = [actionTuple]


procedure = 0
'''
niveau de procedure : 0 => normal
                      1 => action a été choisi
'''

selected = None
'''
[0] => Personnage (le lien à l'objet)
[1] => nomCase  (un string)
'''

choice = None
'''
liste des noms des cases possibles pour l'action
ex : ["A1", "A2", "B1", ... ]
'''

action = None
'''
le nom de l'action
Ex "Mouvement"
'''

damier = {}
'''
damier[case][0] => Case
damier[case][1] => Personnage
'''

tour = 0         # les tours du jeu

prochainPersonnage = ""

deroulement = {}
'''
    le déroulement est un dictionnaire de liste de tuple.
    Il permet de connaître l'ordre dans lequel va se dérouler les actions.
Les clefs du dictionnaire sont les moments où les actions doivent se derouler :
    => des entiers ou des float.

Une action est un tuple dans lequel on trouve :
    1°) Le nom de celui qui va effectuer l'action,
    2°) Le nom de l'action à effectuer (baffe, bouleDeFeu, soin)
    3°) La cible de l'action (None lorsqu'il n'y a pas de cible pour le sort)
Ex :
deroulement[1] : [('Asura',  'tourDeJeu', None)]
deroulement[2] : [('Mantas', 'coupEpee', 'Shu'),
                  ('Shu', 'protectionUltime_VS_coupEpee', None) ]
 
    ================
    fonctionnement :
    ================
    
        Le jeu regarde le plus petit élément de la liste deroulement.keys()
    Cela lui donne une liste de tupleAction.
        Lorsque il y a plusieurs élément dans cette liste, le sort en ai jeté
    et random choisiera qui aura la chance de lancer son sorten premier.
    (=> random non implémenté)
'''


terrain = {\
                "largeur"  : 10,
                "longueur" : 8,
                "A1":"Herbe" , "B1":"Herbe" , "C1":"Herbe" , "D1":"Herbe", #1
                "E1":"Rocher", "F1":"Herbe" , "G1":"Herbe" , "H1":"Herbe",
                "I1":"Herbe" , "J1":"Herbe" , 
                "A2":"Herbe" , "B2":"Herbe" , "C2":"Herbe" , "D2":"Herbe", #2
                "E2":"Sable" , "F2":"Sable" , "G2":"Sable" , "H2":"Herbe",
                "I2":"Herbe" , "J2":"Herbe" ,
                "A3":"Herbe" , "B3":"Herbe" , "C3":"Herbe" , "D3":"Herbe", #3
                "E3":"Sable" , "F3":"Sable" , "G3":"Sable" , "H3":"Herbe",
                "I3":"Herbe" , "J3":"Herbe" ,
                "A4":"Herbe" , "B4":"Herbe" , "C4":"Herbe" , "D4":"Sable", #4
                "E4":"Sable" , "F4":"Sable" , "G4":"Rocher", "H4":"Herbe",
                "I4":"Herbe" , "J4":"Herbe" ,
                "A5":"Herbe" , "B5":"Herbe" , "C5":"Eau"   , "D5":"Eau"  , #5
                "E5":"Eau"   , "F5":"Herbe" , "G5":"Herbe" , "H5":"Herbe",
                "I5":"Herbe" , "J5":"Herbe" ,
                "A6":"Eau"   , "B6":"Eau"   , "C6":"Eau"   , "D6":"Eau"  , #6
                "E6":"Eau"   , "F6":"Herbe" , "G6":"Herbe" , "H6":"Herbe",
                "I6":"Rocher", "J6":"Rocher",
                "A7":"Eau"   , "B7":"Eau"   , "C7":"Eau"   , "D7":"Eau"  , #7
                "E7":"Herbe" , "F7":"Herbe" , "G7":"Herbe" , "H7":"Herbe",
                "I7":"Rocher", "J7":"Rocher",
                "A8":"Eau"   , "B8":"Eau"   , "C8":"Herbe" , "D8":"Herbe", #8
                "E8":"Herbe" , "F8":"Herbe" , "G8":"Herbe" , "H8":"Herbe",
                "I8":"Rocher", "J8":"Rocher"
                }


app = QtGui.QApplication(sys.argv)

# ======================= mainWindow - part 1 ====================
mainWindow = QtGui.QWidget()
mainWindow.resize(905, 705)

# ============================== UI ==============================
# ================================================================
uiPerso1   = UiPerso(mainWindow, "personnage selectionne")
uiPerso2   = UiPerso(mainWindow, "personnage cible")
uiAction   = UiAction(mainWindow)
uiCase     = UiCase(mainWindow)
uiTour     = UiTour(mainWindow)
uiActivite = UiActivite(mainWindow)
uiDamier   = UiDamier(mainWindow)

# ========================= mainWindow - part 2 ======================
mainGrid = QtGui.QGridLayout()
#mainGrid.setSpacing(5)
mainGrid.addWidget(uiDamier,   0,0,6,8)
mainGrid.addWidget(uiPerso1,   6,0,2,2)
mainGrid.addWidget(uiPerso2,   6,2,2,2)
mainGrid.addWidget(uiAction,   6,4,2,4)
mainGrid.addWidget(uiCase,     6,8,2,2)
mainGrid.addWidget(uiActivite, 1,8,5,2)
mainGrid.addWidget(uiTour,     0,8,1,2)
mainWindow.setLayout(mainGrid)
mainWindow.setWindowTitle('TheShinProject - Prototype')
mainWindow.show()


# ============================== DEBUT PARTIE ==========================
# ======================================================================
ajoutePersonnage(Personnage("Guerrier",    "Nain"),        "A1")
ajoutePersonnage(Personnage("Archer",      "Elfe"),        "B3")
ajoutePersonnage(Personnage("Mage",        "Mort-Vivant"), "I7")
ajoutePersonnage(Personnage("DeathKnight", "BloodElfe"),   "J4")

calculOrdreInitialDeJeu()
prochainTour()

sys.exit(app.exec_())
